package com.rongji.dfish.misc.util.json.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.*;
import com.rongji.dfish.base.util.LogUtil;
import com.rongji.dfish.base.util.Utils;
import com.rongji.dfish.base.util.json.impl.AbstractJsonBuilder;

import java.util.*;

/**
 * Json对象构建器采用gson实现
 * @author lamontYu
 * @since DFish5.0
 */
public class JsonBuilder4Gson extends AbstractJsonBuilder {

    private Map<String, Gson> gsonMap = new HashMap<>();

    private Gson getGson() {
        Gson gson = gsonMap.get(dateFormat);
        if (gson == null) {
            gson = new GsonBuilder().setDateFormat(dateFormat).create();
            gsonMap.put(dateFormat, gson);
        }
        return gson;
    }

    @Override
    public String toJson(Object obj) {
        return getGson().toJson(obj);
    }

    @Override
    public <T> T parseObject(String json, Class<T> objClass) {
        if (Utils.isEmpty(json)) {
            return null;
        }
        T obj = getGson().fromJson(json, objClass);
        return obj;
    }

    @Override
    public <T> List<T> parseArray(String json, Class<T> objClass) {
        if (Utils.isEmpty(json)) {
            return new ArrayList<>(0);
        }
        JsonArray jsonArray = new JsonParser().parse(json).getAsJsonArray();
        List<T> objList = new ArrayList<>(jsonArray.size());
        Gson gson = getGson();
        for (JsonElement jsonElement : jsonArray) {
            objList.add(gson.fromJson(jsonElement, objClass));
        }
        return objList;
    }

    @Override
    public Map<String, String> parseAsStringPairs(String json) throws Exception {
        Gson gson = getGson();
        JsonElement elem = gson.toJsonTree(json);
        LinkedHashMap<String, String> ret = new LinkedHashMap<>();
        visit4StringPairs(elem, null, ret);
        return ret;
    }

    private void visit4StringPairs(JsonElement elem, String prefix, LinkedHashMap<String, String> ret) {

        if (elem instanceof JsonObject) {
            JsonObject node = (JsonObject) elem;
            for (String key : node.keySet()) {
                String currentKey = prefix == null ? key : (prefix + "." + key);
                visit4StringPairs(node.get(key), currentKey, ret);
            }
        } else if (elem instanceof JsonArray) {
            JsonArray node = (JsonArray) elem;
            for (int i = 0; i < node.size(); i++) {
                String currentKey = prefix == null ? String.valueOf(i) : (prefix + "." + i);
                visit4StringPairs(node.get(i), currentKey, ret);
            }
        } else {
            if (elem != null) {
                ret.put(prefix, elem.getAsString());
            }
        }
    }

    @Override
    public Object parseObject(String json) throws Exception {
        Gson gson = getGson();
        JsonElement elem = gson.toJsonTree(json);
        return visit(elem);
    }

    private Object visit(JsonElement elem) {
        if (elem instanceof JsonObject) {
            JsonObject node = (JsonObject) elem;
            Map<String, Object> ret = new LinkedHashMap<>(node.keySet().size());
            for (String key : node.keySet()) {
                ret.put(key, visit(node.get(key)));
            }
            return ret;
        } else if (elem instanceof JsonArray) {
            JsonArray node = (JsonArray) elem;
            List<Object> ret = new ArrayList<>(node.size());
            ;
            for (int i = 0; i < node.size(); i++) {
                ret.add(visit(node.get(i)));
            }
            return ret;
        } else if (elem instanceof JsonPrimitive) {
            JsonPrimitive primitive = (JsonPrimitive) elem;
            if (primitive.isNumber()) {
                return primitive.getAsNumber();
            } else if (primitive.isString()) {
                return primitive.getAsString();
            } else if (primitive.isBoolean()) {
                return primitive.getAsBoolean();
            }
        } else if (elem.isJsonNull()) {
            return null;
        }
        LogUtil.info("不可识别的类型:" + elem.getClass().getName());
        return null;
    }
}
